"""
模板配置依赖检查工具

这个工具用于检查Jinja2模板文件中引用的配置在meta.json中是否存在。

功能:
1. 从模板文件中提取所有配置路径
2. 检查这些配置路径在meta.json中是否已存在
3. 将缺失的配置按照meta.json的结构组织并输出

使用方式:
python3 miaoma.py analyze-template --directory <directory>

参数说明:
- directory: 测试用例目录路径,包含template.j2和meta.auto.json文件

示例:
python3 miaoma.py analyze-template --directory assets/gen-code-check/AddOrEdit

输出格式:
{
    "table": {
        "common": {
            "entity_name": null
        }
    },
    "columns": {
        "student_name": {
            "common": {
                "label": null
            }
        }
    }
}
"""

import re
import json
from pathlib import Path
import argparse
from src.core.command import Command
from src.base.registry import bera
import os
from datetime import datetime
import json
import re

logger = bera.logger

class AnalyzeTemplateConfigCommand(Command):
    """分析模板配置命令"""

    def __init__(self):
        super().__init__()
        self.name = "analyze-template"
        self.group = "代码生成"
        self.help = "分析模板配置"
        self.description = """
        分析模板配置。该命令会:
        1. 从template.j2中提取所有配置路径
        2. 检查这些配置在meta.auto.json中是否存在
        3. 将缺失的配置按meta.json结构输出到文件
        """

    def add_arguments(self, parser):
        """添加命令参数"""
        parser.add_argument('--directory', '-d',
                          default='assets/gen-code-check/AddOrEdit',
                          help='测试用例目录路径')

    def execute(self, args):
        """执行命令"""
        try:
            bera.logger.info("开始执行analyze-template命令")

            # 构建文件路径
            test_dir = Path(args.directory)
            if not test_dir.exists():
                raise FileNotFoundError(f"错误: 测试目录 {args.directory} 不存在")

            template_file = test_dir / 'template.j2'
            meta_file = test_dir / 'meta.auto.json'

            # 修改输出目录到artifacts
            artifacts_dir = Path('artifacts/analyze-template') / test_dir.name
            artifacts_dir.mkdir(parents=True, exist_ok=True)
            output_file = artifacts_dir / 'missing_configs.json'

            # 检查必要文件是否存在
            if not all(f.exists() for f in [template_file, meta_file]):
                raise FileNotFoundError("错误: 缺少必要的文件 (template.j2, meta.auto.json)")

            self.run(template_file, meta_file, output_file)
            bera.logger.info("analyze-template命令执行完成")
        except Exception as e:
            if hasattr(args, 'verbose') and args.verbose:
                import traceback
                traceback.print_exc()
            raise

    def read_file(self, file_path):
        """读取文件内容"""
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()

    def read_json(self, file_path):
        """读取JSON文件"""
        with open(file_path, 'r', encoding='utf-8') as f:
            return json.load(f)

    def write_json(self, file_path, data):
        """写入JSON文件"""
        # 确保输出目录存在
        output_dir = Path(file_path).parent
        output_dir.mkdir(parents=True, exist_ok=True)

        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)

    def extract_configs(self, template_file):
        """从模板文件中提取所有配置路径"""
        content = self.read_file(template_file)

        # 提取 {{}} 中的配置
        var_pattern = r'{{\s*([^}]+)\s*}}'
        var_matches = re.findall(var_pattern, content)

        # 提取 {% if %} 中的配置
        if_pattern = r'{%\s*if\s+([^%]+)\s*%}'
        if_matches = re.findall(if_pattern, content)

        # 提取 {% for %} 中的配置
        for_pattern = r'{%\s*for\s+(\w+)(?:,\s*\w+)?\s+in\s+([^%]+)\s*%}'
        for_matches = re.findall(for_pattern, content)

        configs = set()

        # 处理所有匹配项
        for match in var_matches + if_matches:
            # 去除过滤器和空格
            parts = match.split('|')[0].strip().split()
            if parts:
                config_path = parts[0].strip()
                if config_path.startswith('table.'):
                    configs.add(config_path)
                elif config_path.startswith('field.'):
                    # 将field.xxx转换为columns.*.xxx
                    parts = config_path.split('.')
                    if len(parts) > 1:
                        configs.add(f"columns.*.{'.'.join(parts[1:])}")

        # 处理for循环
        for var_name, collection in for_matches:
            collection = collection.strip()
            if collection == 'columns.items()':
                # 在循环体中搜索使用field的配置
                loop_pattern = fr'{{\s*field\.([^}}]+)\s*}}'
                loop_matches = re.findall(loop_pattern, content)
                for match in loop_matches:
                    configs.add(f"columns.*.{match.strip()}")

        return sorted(list(configs))

    def check_config_exists(self, config_path, meta_data):
        """检查配置路径在meta数据中是否存在"""
        parts = config_path.split('.')

        # 处理表级配置
        if parts[0] == 'table':
            current = meta_data.get('table', {})
            for part in parts[1:]:
                if part not in current:
                    return False
                current = current[part]
            return True

        # 处理字段级配置
        elif parts[0] == 'columns' and parts[1] == '*':
            field_parts = parts[2:]
            # 检查所有字段是否都有这个配置
            for field_name, field_data in meta_data.get('columns', {}).items():
                current = field_data
                for part in field_parts:
                    if part not in current:
                        return False
                    current = current[part]
            return True

        return False

    def build_missing_config(self, config_path, meta_data):
        """构建缺失配置的结构"""
        parts = config_path.split('.')
        result = {}

        # 处理表级配置
        if parts[0] == 'table':
            if 'table' not in result:
                result['table'] = {}
            current = result['table']

            for part in parts[1:-1]:
                if part not in current:
                    current[part] = {}
                current = current[part]
            current[parts[-1]] = None

        # 处理字段级配置
        elif parts[0] == 'columns' and parts[1] == '*':
            field_parts = parts[2:]
            if 'columns' not in result:
                result['columns'] = {}

            # 为每个缺少配置的字段创建结构
            for field_name, field_data in meta_data.get('columns', {}).items():
                current = field_data
                missing = False
                for part in field_parts:
                    if part not in current:
                        missing = True
                        break
                    current = current[part]

                if missing:
                    current = result['columns'][field_name] = {}
                    for part in field_parts[:-1]:
                        current[part] = {}
                        current = current[part]
                    current[field_parts[-1]] = None

        return result

    def merge_configs(self, config1, config2):
        """合并两个配置结构"""
        if isinstance(config1, dict) and isinstance(config2, dict):
            result = config1.copy()
            for key, value in config2.items():
                if key in result:
                    if isinstance(value, dict):
                        result[key] = self.merge_configs(result[key], value)
                    else:
                        result[key] = value
                else:
                    result[key] = value
            return result
        return config2

    def save_missing_configs(self, missing_configs, template_file):
        """保存缺失的配置到文件"""
        # 获取模板文件所在目录名
        template_dir = os.path.basename(os.path.dirname(template_file))

        # 生成带时间戳的文件名
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        output_dir = f'artifacts/analyze-template/{template_dir}'
        output_file = f'missing_configs_{timestamp}.json'
        output_path = os.path.join(output_dir, output_file)

        # 创建输出目录
        os.makedirs(output_dir, exist_ok=True)

        # 写入文件
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(missing_configs, f, indent=2, ensure_ascii=False)

        logger.info(f'\n已将缺失的配置写入: {output_path}')

    def run(self, template, meta, output):
        """运行命令"""
        logger.info('开始执行analyze-template命令')

        # 提取配置路径
        configs = self.extract_configs(template)
        logger.info('\n从模板中提取的配置路径:')
        for config in configs:
            logger.info(f'- {config}')

        # 检查配置
        meta_data = self.read_json(meta)
        missing_configs = {}
        for config in configs:
            if not self.check_config_exists(config, meta_data):
                config_structure = self.build_missing_config(config, meta_data)
                missing_configs = self.merge_configs(missing_configs, config_structure)

        # 输出结果
        logger.info('\n缺失的配置:')
        logger.info(json.dumps(missing_configs, indent=2, ensure_ascii=False))

        # 保存缺失的配置
        self.save_missing_configs(missing_configs, template)

        logger.info('analyze-template命令执行完成')

# 注册命令
bera.register("analyze-template", AnalyzeTemplateConfigCommand())